#include "iot_errno.h"
#include "iot_i2c.h"
#include "stm32f4xx_ll_i2c.h"
#include "ll_i2c.h"
#include "stdio.h"

/*****************************************************
Tabel I2C-Pin about stm32f407 gpio alternate for I2C
┏━━━━━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┓
┃   function    ┃   pin     ┃  pin      ┃   pin     ┃
┠━━━━━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┨
┃   I2C1_SCL    ┃   PB6     ┃  PB8      ┃           ┃
┃   I2C1_SDA    ┃   PB7     ┃  PB9      ┃           ┃
┠━━━━━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┨
┃   I2C2_SCL    ┃   PB10    ┃  PF1      ┃   PH4     ┃
┃   I2C2_SDA    ┃   PB11    ┃  PF0      ┃   PH5     ┃
┠━━━━━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┼━━━━━━━━━━━┨
┃   I2C3_SCL    ┃   PA8     ┃  PH7      ┃           ┃
┃   I2C3_SDA    ┃   PC9     ┃  PH8      ┃           ┃
┗━━━━━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━━━━━━┛
*****************************************************/
/*
    LL_I2C_IsActiveFlag_SB(I2C_TypeDef *I2Cx);
    LL_I2C_IsActiveFlag_ADDR(I2C_TypeDef *I2Cx);
    LL_I2C_IsActiveFlag_BTF(I2C_TypeDef *I2Cx);
    LL_I2C_IsActiveFlag_BUSY(I2C_TypeDef *I2Cx);
    LL_I2C_IsActiveFlag_MSL(I2C_TypeDef *I2Cx);
    LL_I2C_GenerateStartCondition(I2C_TypeDef *I2Cx);
    LL_I2C_GenerateStopCondition(I2C_TypeDef *I2Cx);
    LL_I2C_TransmitData8(I2C_TypeDef *I2Cx, uint8_t Data);
    LL_I2C_IsActiveFlag_RXNE(I2C_TypeDef *I2Cx);
    LL_I2C_IsActiveFlag_TXE(I2C_TypeDef *I2Cx);
    LL_I2C_AcknowledgeNextData(I2C_TypeDef *I2Cx, uint32_t TypeAcknowledge);
 */

static uint8_t I2C_AutoEndMode[I2C_MAX] = {1, 1, 1};
extern I2C_Config g_i2cConfig[I2C_MAX];

void IOT_I2C_EnableAutoEndMode(uint8_t id)
{
    // 参数检查
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    I2C_AutoEndMode[id - 1] = 1;
}
void IOT_I2C_DisableAutoEndMode(uint8_t id)
{
    // 参数检查
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    I2C_AutoEndMode[id - 1] = 0;
}

unsigned int IoTI2cWrite(unsigned int id, unsigned short deviceAddr, const unsigned char *data, unsigned int dataLen)
{
    // 参数检查
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }

    uint64_t start_tick, end_tick;
    // 起始信号
    LL_I2C_GenerateStartCondition(g_i2cConfig[id-1].I2Cx);
    start_tick = LL_GetTick();
    while (!LL_I2C_IsActiveFlag_SB(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : Generate start condition failed..\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    // 等待进入master模式
    start_tick = LL_GetTick();
    while (!LL_I2C_IsActiveFlag_MSL(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : I2C can not goto master mode...\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    // 发送从机地址
    LL_I2C_TransmitData8(g_i2cConfig[id-1].I2Cx, (deviceAddr << 1) & 0xff);
    start_tick = LL_GetTick();
    // 等待从机地址发送完毕
    while (!LL_I2C_IsActiveFlag_ADDR(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : send slave addr timeout...\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    // 清空addr标记位
    LL_I2C_ClearFlag_ADDR(g_i2cConfig[id-1].I2Cx);
    // 发送数据
    for (uint32_t i = 0; i < dataLen; i++)
    {
        // 写入数据
        LL_I2C_TransmitData8(g_i2cConfig[id-1].I2Cx, data[i]);
        // 等待数据寄存器为空
        start_tick = LL_GetTick();
        while (!LL_I2C_IsActiveFlag_TXE(g_i2cConfig[id-1].I2Cx))
        {
            end_tick = LL_GetTick();
            // 等待超时
            if (end_tick - start_tick > 1000 * 10)
            {
                printf("%s line %d error : send date timeout...\n", __func__, __LINE__);
                return IOT_FAILURE;
            }
        }
    }
    if (I2C_AutoEndMode[id-1])
    {
        // 结束信号
        LL_I2C_GenerateStopCondition(g_i2cConfig[id-1].I2Cx);
    }
    return 0;
}

unsigned int IoTI2cRead(unsigned int id, unsigned short deviceAddr, unsigned char *data, unsigned int dataLen)
{
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    uint64_t start_tick, end_tick;
    // LL_I2C_SetOwnAddress1(g_i2cConfig[id-1].I2Cx, ((deviceAddr<<1)|1)&0xff, LL_I2C_OWNADDRESS1_7BIT);
    //  起始信号
    LL_I2C_GenerateStartCondition(g_i2cConfig[id-1].I2Cx);
    start_tick = LL_GetTick();
    while (!LL_I2C_IsActiveFlag_SB(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : Generate start condition failed..\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    // 等待进入master模式
    start_tick = LL_GetTick();
    while (!LL_I2C_IsActiveFlag_MSL(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : I2C can not goto master mode...\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    // 发送从机地址
    LL_I2C_TransmitData8(g_i2cConfig[id-1].I2Cx, ((deviceAddr << 1) | 1) & 0xff);
    start_tick = LL_GetTick();
    // 等待从机地址发送完毕
    while (!LL_I2C_IsActiveFlag_ADDR(g_i2cConfig[id-1].I2Cx))
    {
        end_tick = LL_GetTick();
        // 等待超时
        if (end_tick - start_tick > 1000 * 10)
        {
            printf("%s line %d error : send slave addr timeout...\n", __func__, __LINE__);
            return IOT_FAILURE;
        }
    }
    if (dataLen == 1) // 只接受一个字节，需要再清除addr标志前后做相应的操作，来源于数据手册
    {
        // 设置非应答
        LL_I2C_AcknowledgeNextData(g_i2cConfig[id-1].I2Cx, LL_I2C_NACK);
        // 清空addr标记位
        LL_I2C_ClearFlag_ADDR(g_i2cConfig[id-1].I2Cx);
        // 生成停止条件
        LL_I2C_GenerateStopCondition(g_i2cConfig[id-1].I2Cx);
    }
    else
    {
        // 清空addr标记位
        LL_I2C_ClearFlag_ADDR(g_i2cConfig[id-1].I2Cx);
    }

    for (uint32_t i = 0; i < dataLen; i++)
    {
        start_tick = LL_GetTick();
        // 等待接收标记不为空
        while (!LL_I2C_IsActiveFlag_RXNE(g_i2cConfig[id-1].I2Cx))
        {
            end_tick = LL_GetTick();
            // 等待超时
            if (end_tick - start_tick > 1000 * 10)
            {
                printf("%s line %d error : I2C can not get enough data...\n", __func__, __LINE__);
                return IOT_FAILURE;
            }
        }
        // 读取数据
        data[i] = LL_I2C_ReceiveData8(g_i2cConfig[id-1].I2Cx);
        // 倒数第2个，设置非应答，停止位，来源于数据手册
        if (i == dataLen - 2)
        {
            LL_I2C_AcknowledgeNextData(g_i2cConfig[id-1].I2Cx, LL_I2C_NACK);
            LL_I2C_GenerateStopCondition(g_i2cConfig[id-1].I2Cx);
        }
    }

    return IOT_SUCCESS;
}

unsigned int IoTI2cInit(unsigned int id, unsigned int baudrate)
{
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 波特率必须小于400k
    if (baudrate > 400 * 1000)
    {
        printf("%s line %d error : bad i2c baudrate, for stm32f407 i2c baudrate must lower than 400k...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 初始化GPIO引脚
    if (LL_I2C_PIN_CONFIG(id) != SUCCESS)
    {
        printf("%s line %d error : init I2C pin failed...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 打开I2C时钟
    LL_APB1_GRP1_EnableClock(LL_GET_I2C_CLK(id));
    // 禁止广播呼叫
    LL_I2C_DisableGeneralCall(g_i2cConfig[id-1].I2Cx);
    // 使能时钟延长
    LL_I2C_EnableClockStretching(g_i2cConfig[id-1].I2Cx);
    // 模式
    g_i2cConfig[id-1].li2c.PeripheralMode = LL_I2C_MODE_I2C;
    // 波特率
    g_i2cConfig[id-1].li2c.ClockSpeed = baudrate;
#if defined(I2C_FLTR_ANOFF)
    // 模拟滤波器
    g_i2cConfig[id-1].li2c.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
    // 数字滤波器
    g_i2cConfig[id-1].li2c.DigitalFilter = 0;
#endif
    // 自己的地址
    g_i2cConfig[id-1].li2c.OwnAddress1 = 0;
    // 应答
    g_i2cConfig[id-1].li2c.TypeAcknowledge = LL_I2C_ACK;
    // 地址位
    g_i2cConfig[id-1].li2c.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
    if (LL_I2C_Init(g_i2cConfig[id-1].I2Cx, &(g_i2cConfig[id-1].li2c)) != SUCCESS)
    {
        printf("%s line %d error : LL_I2C_Init init I2C failed...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 启用自动结束，数据传输完成后，自动生成一个停止条件
    // LL_I2C_EnableAutoEndMode(g_i2cConfig[id-1].I2Cx);
    // 启动I2C
    LL_I2C_Enable(g_i2cConfig[id-1].I2Cx);

    printf("**************************************************************************\n");
    printf("* I2C init success! Please pay attention to the following information    *\n");
    printf("**************************************************************************\n");
    printf("* Use default config for I2C, see Tabel I2C-Pin.                         *\n");
    printf("* For stm32f407 uart I2C port is 1~3                                     *\n");
    printf("* If you want change i2c pin, please modify macro in hal_i2c.h:          *\n");
    printf("*    I2Cx_SDA for I2C SDA pin id. eg: I2C1_SDA/I2C2_SDA..                *\n");
    printf("*    I2Cx_SCL for I2C SCL pin id. eg: I2C2_SCL/I2C2_SCL..                *\n");
    printf("* About pin id, see iot_gpio driver                                      *\n");
    printf("**************************************************************************\n");

    return IOT_SUCCESS;
}

unsigned int IoTI2cDeinit(unsigned int id)
{
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 复位GPIO
    GPIO_TypeDef* GPIOx = LL_GET_GPIOX((g_i2cConfig[id-1].scl)/16);
    if(LL_GPIO_DeInit(GPIOx) != SUCCESS){
        printf("%s error : LL_GPIO_DeInit I2C Pin SCL failed\n", __func__);
        return IOT_FAILURE;
    }
    GPIOx = LL_GET_GPIOX((g_i2cConfig[id-1].sda)/16);
    if(LL_GPIO_DeInit(GPIOx) != SUCCESS){
        printf("%s error : LL_GPIO_DeInit I2C Pin SDA failed\n", __func__);
        return IOT_FAILURE;
    }
    // 复位I2C
    if (LL_I2C_DeInit(g_i2cConfig[id-1].I2Cx) != SUCCESS)
    {
        printf("%s line %d error : LL_I2C_DeInit failed...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    return IOT_SUCCESS;
}

unsigned int IoTI2cSetBaudrate(unsigned int id, unsigned int baudrate)
{
    if (id > I2C_MAX || id < 1)
    {
        printf("%s line %d error : bad i2c id, for stm32f407 i2c id is 1/2/3...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 波特率
    g_i2cConfig[id-1].li2c.ClockSpeed = baudrate;
    if (LL_I2C_Init(g_i2cConfig[id-1].I2Cx, &(g_i2cConfig[id-1].li2c)) != SUCCESS)
    {
        printf("%s line %d error : LL_I2C_Init init I2C failed...\n", __func__, __LINE__);
        return IOT_FAILURE;
    }

    return IOT_SUCCESS;
}